package com.ibeetl.eval;

import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.exception.BeetlException;
import org.beetl.core.exception.ErrorInfo;
import org.beetl.core.resource.StringTemplateResourceLoader;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;

import com.ibeetl.eval.fn.LookupFunction;
import com.ibeetl.eval.worker.BlockNodeWorker;
import com.ibeetl.eval.worker.ExpressNodeWorker;
import com.ibeetl.eval.worker.ScriptNodeWorker;
import com.ibeetl.eval.worker.SimpleDecisionNodeWorker;
import com.ibeetl.eval.worker.SumNodeWorker;
/**

import com.ibeetl.eval.worker.ExpressNodeWorker; * 目前不具备保留中间结算结果到TreeNode，导致不能互相引用
 * @author xiandafu
 *
 */
public class EvalEngine {
	public static GroupTemplate gt = null;
	public static Map<String,NodeWorker> nodeFactory = new HashMap<String,NodeWorker>();
	static {
		nodeFactory.put("sum", new SumNodeWorker());
		nodeFactory.put("express", new ExpressNodeWorker());
		nodeFactory.put("script", new ScriptNodeWorker());
		nodeFactory.put("block", new BlockNodeWorker());
		nodeFactory.put("treeDecision", new SimpleDecisionNodeWorker());
	}
	static {
		 try {
			 Configuration conf =  Configuration.defaultConfiguration();
			 conf.setEngine("com.ibeetl.eval.EvalTemplateEngine");
			gt = new GroupTemplate(new StringTemplateResourceLoader(),conf);
			gt.registerFunction("lookup", new LookupFunction());
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	public TreeNode run(Reader reader,Map<String,Object> paras) throws Exception{
		Document doc = getXML(reader);
		Element workspaceEle = doc.getRootElement();
		Element projectEle = workspaceEle.getChild("project");
		Map defineVars = getProjectVarDefine(projectEle);
		Map ctxMap = this.merage(paras, defineVars);

		Element docEle = projectEle.getChild("doc");
		
		EvalContext  ctx = new EvalContext(this,ctxMap);
//		TreeNode node =  ctx.enter(docEle.getAttributeValue("name"), docEle);
		TreeNode node = this.processRule(docEle, ctx);
//		ctx.exist();
		return node;
	
		
	}
	
	public String validate(Reader reader) throws Exception{
		Document doc = getXML(reader);
		Element workspaceEle = doc.getRootElement();
		Element projectEle = workspaceEle.getChild("project");
		Element docEle = projectEle.getChild("doc");
		StringBuilder error = new StringBuilder();
		validateElement(docEle,error);
		return error.toString();
	
		
	}
	
	private void validateElement(Element ruleEle,StringBuilder error ){
		List<Element> list = ruleEle.getChildren();
		if(list.size()==0){
			String name = ruleEle.getAttributeValue("name");
			String f  = ruleEle.getAttributeValue("f");
			if(f==null){
				f = "express";
			}
			NodeWorker worker = nodeFactory.get(f);
			String script = worker.getScript(ruleEle);
			BeetlException exception = gt.validateScript(script);
			if(exception==null){
				//语法没问题
				return ;
			}
			ErrorInfo errorInfo = new ErrorInfo(exception);
			error.append("[规则节点:"+name+"]");
			error.append("[错误符号:  ").append(errorInfo.getErrorTokenText()).append("  ]");
			error.append("[错误信息:"+errorInfo.getMsg()+"]");
			error.append("[错误行数:"+errorInfo.getErrorTokenLine()+"]");
			error.append("\n");
			return ;
		}
		for(Element ele:list){
			validateElement(ele,error);
		}
		
		
	}
	
	
	
	private Document getXML(Reader reader) throws Exception {
		SAXBuilder jdomBuilder = new SAXBuilder();
		 
        Document jdomDocument = jdomBuilder.build(reader);
        return jdomDocument;
	}
	
	/**
	 * 得到每个评级预先定义的变量
	 * @param projectEle
	 * @return
	 */
	private Map getProjectVarDefine(Element projectEle){
		return Collections.emptyMap();
	}
	
	public NodeWorker getRuleNode(Element ruleEle){
		String function = ruleEle.getAttributeValue("f");
		if(function==null){
			function = "express";
		}
		NodeWorker node = nodeFactory.get(function);
		if(node==null){
			throw new RuntimeException(function+" 不支持"+ruleEle.getAttributeValue("name"));
		}
		return node;
	}
	
	public List<TreeNode> processChildren(List<Element> list,EvalContext ctx){
		List<TreeNode> rets = new ArrayList<TreeNode>();
		for(Element rule:list){
			TreeNode object = processRule(rule,ctx);
			rets.add(object);
		}
		
		return rets;
		
	}
	
	public TreeNode processRule(Element ruleEle,EvalContext ctx) {
		//变量名字
		String name = ruleEle.getAttributeValue("name");
		String f  = ruleEle.getAttributeValue("f");
		if(f==null){
			f = "express";
		}
		NodeWorker worker = nodeFactory.get(f);
		if(worker==null){
			throw new XmlEvalException(ruleEle, "未能找到指定处理类");
		}
		TreeNode node = worker.execute(ruleEle, ctx);
		return node;

	}
	
	
	
	
	protected  Map<String,Object> merage(Map<String,Object> para,String newName,Object newValue){
		Map<String,Object> newMap = new HashMap<String,Object>();
		newMap.putAll(para);
		newMap.put(newName, newValue);
		return newMap;
	}
	protected Map<String,Object> merage(Map<String,Object> para,Map map){
		Map<String,Object> newMap = new HashMap<String,Object>();
		//todo 变量已经定义
		newMap.putAll(para);
		newMap.putAll(map);
		return newMap;
	}
	
	protected Map<String,Object> newMap(Map<String,Object> para){
		Map<String,Object> newMap = new HashMap<String,Object>();
		
		newMap.putAll(para);
		return newMap;
	}
	

	
}
